import datetime
import operator
import Crypto
from google.appengine.ext import db
from google.appengine.api import users
from . import Item

class Message(db.Model):
	"""represents a message thread between users"""
	thread_id = db.StringProperty(required=True)
	sender = db.UserProperty(required=True, auto_current_user_add=True)
	recipient = db.UserProperty(required=True)
	datetime = db.DateTimeProperty(required=True, auto_now_add=True)
	content = db.TextProperty()
	item = db.ReferenceProperty(Item.Item)
	read = db.BooleanProperty()

	@classmethod
	def getMessages(cls, user, inbox=True, sent=True):
		def orderedGenerator(queries, field, dir):
			objs = []
			# Get first item from each query
			for query in queries:
				try:
					objs.append(query.next())
				except StopIteration:
					# Remove empty queries
					try:
						queries.remove(query)
					except ValueError:
						pass

			dir = True if dir == 'DESC' else False
			while filter(None, objs):
				obj = sorted(objs, key=operator.attrgetter(field), reverse=dir)[0]
				index = objs.index(obj)
				try:
					objs[index] = queries[index].next()
				except StopIteration:
					# Query exhausted, remove it from list
					queries.remove(index)
					objs.remove(index)
				yield obj

		queries = []
		if inbox:
			q = cls.all()
			q.filter('recipient = ', user)
			q.order('datetime')
			queries.append(q.run())
		if sent:
			q = cls.all()
			q.filter('sender = ', user)
			q.order('datetime')
			queries.append(q.run())

		return orderedGenerator(queries, 'datetime', 'DESC')

	@classmethod
	def get_unique_conversations(cls, user, inbox=True, sent=True):
		def unique_generator():
			ids = set()
			query = cls.getMessages(user, inbox, sent)
			for m in query:
				if m.thread_id not in ids:
					ids.add(m.thread_id)
					yield m
		return unique_generator()

	@classmethod
	def getThread(cls, id):
		q = cls.all()
		q.filter('thread_id = ', id)
		q.order('datetime')
		return q

	def __init__(self, *args, **kwargs):
		if 'thread_id' not in kwargs:
			randomSalt = Crypto.Random.new().read(32)
			h = Crypto.Hash.SHA256.new()
			# using hash of sender, recipient, datetime, and random salt to create thread_id
			h.update(str(datetime.datetime.now()))
			h.update(str(kwargs['recipient'].user_id()))
			h.update(str(users.get_current_user().user_id()))
			h.update(randomSalt)
			kwargs['thread_id'] = h.hexdigest()

		super(Message, self).__init__(**kwargs)

	def reply(self, content, current_user):
		x = Message(
			recipient=self.sender if self.recipient == current_user else self.recipient,
			thread_id=self.thread_id,
			content=content,
			item=self.item,
			read=False
		)
		x.put()
